package com.hhit.yb.compose_demo.views.state

import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.CutCornerShape
import androidx.compose.material.Button
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.SideEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.shadow
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.hhit.yb.compose_demo.views.StyleableTutorialText
import com.hhit.yb.compose_demo.views.getRandomColor

@Composable
fun Tutorial4_2_4Screen() {
    Column(
        modifier = Modifier.padding(10.dp)
    ) {
        StyleableTutorialText(
            text = "**Stability**, not triggering recomposition when inputs of a " +
                    "function hasn't changed, is achieved" +
                    " by using immutable variables or/and using" +
                    "    @Immutable or @Stable annotation to make functions skippable.\n" +
                    "In the example below **UnStableDataClass(var)** is not skippable because of " +
                    "**UnstableComposable(data = unstableData)**. It " +
                    "recompose even if the input doesn't change.",
            bullets = false
        )
        ComposeScopeSample()
    }
}

@Preview
@Composable
private fun ComposeScopeSample() {
    var counter by remember {
        mutableIntStateOf(0)
    }

    val unstableData by remember {
        mutableStateOf(UnStableDataClass(0))
    }

    val stableData by remember {
        mutableStateOf(StableDataClas(0))
    }

    Column {
        Button(
            modifier = Modifier.fillMaxWidth(),
            onClick = { counter++ }) {
            Text(text = "Counter: $counter")
        }

        Spacer(modifier = Modifier.height(20.dp))
        OuterComposable {
            // This scope never gets recomposed because
            // Nothing is read here
            println("Outer SCOPE")
            MiddleComposable {
                // This scope is recomposed because counter is read in this scope
                println("Middle SCOPE")
                // Unstable Functions get recomposed even when their inputs don't change
                UnstableComposable(data = unstableData)
                StableComposable(data = stableData)
                Counter(text = "Counter $counter")
            }
        }
    }
}

//注意这两个类的参数一个是var一个是val
// 🔥 A class with mutable param is Unstable
data class UnStableDataClass(var value: Int)

// A class with all of its params immutable is Stable
data class StableDataClas(val value: Int)

@Composable
private fun UnstableComposable(data: UnStableDataClass) {
    SideEffect {
        println("🍎 UnstableComposable")
    }
    Column(
        modifier = Modifier
            .padding(4.dp)
            .shadow(1.dp, shape = CutCornerShape(topEnd = 8.dp))
            .background(getRandomColor())
            .fillMaxWidth()
            .padding(4.dp)
    ) {
        Text(text = "UnstableComposable() value: ${data.value}")
    }
}

@Composable
private fun StableComposable(data: StableDataClas) {
    SideEffect {
        println("🍏 StableComposable")
    }
    Column(
        modifier = Modifier
            .padding(4.dp)
            .shadow(1.dp, shape = CutCornerShape(topEnd = 8.dp))
            .background(getRandomColor())
            .fillMaxWidth()
            .padding(4.dp)
    ) {
        Text(text = "StableComposable value(): ${data.value}")
    }
}

@Composable
private fun OuterComposable(
    content: @Composable () -> Unit
) {
    SideEffect {
        println("OUTER COMPOSABLE")
    }

    Column(
        modifier = Modifier
            .padding(4.dp)
            .shadow(1.dp, shape = CutCornerShape(topEnd = 8.dp))
            .background(getRandomColor())
            .fillMaxWidth()
            .padding(4.dp)
    ) {
        content()
    }
}


@Composable
private fun MiddleComposable(
    content: @Composable () -> Unit
) {
    SideEffect {
        println("MIDDLE COMPOSABLE")
    }
    Column(
        modifier = Modifier
            .padding(4.dp)
            .shadow(1.dp, shape = CutCornerShape(topEnd = 8.dp))
            .background(getRandomColor())
            .fillMaxWidth()
            .padding(4.dp)
    ) {
        content()
    }
}

@Composable
private fun Counter(
    text: String
) {
    SideEffect {
        println("Counter()")
    }
    Column(
        modifier = Modifier
            .padding(4.dp)
            .shadow(1.dp, shape = CutCornerShape(topEnd = 8.dp))
            .background(getRandomColor())
            .fillMaxWidth()
            .padding(4.dp)
    ) {
        Text(text = "Counter() text: $text")
    }
}